# install.packages("ggplot2","dplyr")
library(ggplot2)
library(dplyr)
library(tidyr)

Reading in corpus

# R must be at least 3.3.1 for `tm` and `slam` to work.
# install.packages("tm")
# install.packages("SnowballC")
library(tm)
Loading required package: NLP

Attaching package: ‘NLP’

The following object is masked from ‘package:ggplot2’:

    annotate
#system("ls ../input") # do we need this?

Adapted from this Kaggle notebook.

shak<-read.csv("../data/Shakespeare_data.csv",header = TRUE, as.is = TRUE)
#shak<-na.omit(shak)
head(shak)
  Dataline     Play PlayerLinenumber ActSceneLine        Player
1        1 Henry IV               NA                           
2        2 Henry IV               NA                           
3        3 Henry IV               NA                           
4        4 Henry IV                1        1.1.1 KING HENRY IV
5        5 Henry IV                1        1.1.2 KING HENRY IV
6        6 Henry IV                1        1.1.3 KING HENRY IV
                                                                                        PlayerLine
1                                                                                            ACT I
2                                                                     SCENE I. London. The palace.
3 Enter KING HENRY, LORD JOHN OF LANCASTER, the EARL of WESTMORELAND, SIR WALTER BLUNT, and others
4                                                           So shaken as we are, so wan with care,
5                                                       Find we a time for frighted peace to pant,
6                                                   And breathe short-winded accents of new broils

Word frequency

# play level word frequency
plays <- unique(shak$Play)
loveFreq<-numeric()
for (i in 1:length(plays)){
    text <- Corpus(VectorSource(paste(shak[shak$Play==plays[i],]$PlayerLine,collapse=" ")))
    text <- tm_map(text, removePunctuation)
    text <- tm_map(text, PlainTextDocument)
    text <- tm_map(text, removeWords, stopwords('english'))
    
    # stemming to merge all "loved", "loving" into one   
    text <- tm_map(text, stemDocument)
    tdm  <- TermDocumentMatrix(text)
    
    loveFreq[i]<-as.numeric(slam::row_sums(tdm)["love"])
  }
lPlay <- data.frame(plays,loveFreq)
lPlay <- na.omit(lPlay)
# order the plays based on the occurence of love
lPlay<-lPlay[order(-lPlay$loveFreq),]
head(lPlay)
                      plays loveFreq
35  Two Gentlemen of Verona      188
28         Romeo and Juliet      160
6            As you like it      138
22 A Midsummer nights dream      128
17       Loves Labours Lost      125
23   Much Ado about nothing      122
# player level word frequency
players <- unique(shak$Player)
loveFreq <- numeric()
for (i in 1:length(players)){
    text <- Corpus(VectorSource(paste(shak[shak$Player==players[i],]$PlayerLine,collapse=" ")))
    text <- tm_map(text, removePunctuation)
    text <- tm_map(text, PlainTextDocument)
    text <- tm_map(text, removeWords, stopwords('english'))
    text <- tm_map(text,stemDocument)
    
    tdm  <- TermDocumentMatrix(text)
    
    loveFreq[i] <- as.numeric(slam::row_sums(tdm)["love"])
  }
lPlayer <- data.frame(players,loveFreq)
lPlayer <- na.omit(lPlayer)
#order
lPlayer <- lPlayer[order(-lPlayer$loveFreq),]
head(lPlayer)
     players loveFreq
904  PROTEUS       59
190 ROSALIND       57
771    ROMEO       56
169   HELENA       46
906    JULIA       41
650     IAGO       40

Visualising corpus

shak %>%
  group_by(Play) %>%
  summarise(n = n()) %>%
  ggplot(., aes(x=reorder(Play, n),y=n)) +
    geom_bar(stat="identity") +
    coord_flip() +
    ggtitle("Length of Shakespeare's plays") +
    theme(legend.position="none") +
    xlab("Play") +
    ylab("Number of lines")

shak %>%
  filter(Play == "Hamlet") %>%
  group_by(Player) %>%
  summarise(n = n()) %>%
  ggplot(., aes(x=reorder(Player, n),y=n)) +
    geom_bar(stat="identity") +
    coord_flip() +
    ggtitle("Speech in Hamlet") +
    theme(legend.position="none") +
    xlab("Player") +
    ylab("Number of lines")

shak %>%
  group_by(Play,Player) %>%
  summarise(n = n()) %>%
  filter(n > 700) %>%
  ggplot(., aes(x=reorder(Player, n),y=n)) +
    geom_bar(aes(fill=Play),stat="identity") +
    coord_flip() +
    ggtitle("Amount of lines by character") +
#    theme(legend.position="none") +
    xlab("Player") +
    ylab("Number of lines")

lPlay %>%
  ggplot(., aes(x=reorder(plays, loveFreq),y=loveFreq)) +
    geom_bar(aes(fill=plays),stat="identity") +
    coord_flip() +
    ggtitle("Love in each play") +
#    theme(legend.position="none") +
    xlab("Play") +
    ylab("frequency of the word 'love'") +
    theme(legend.position = "none")

lPlayer %>%
  filter(loveFreq > 20) %>%
  ggplot(., aes(x=reorder(players, loveFreq),y=loveFreq)) +
    geom_bar(aes(fill=players),stat="identity") +
    coord_flip() +
    ggtitle("Love in each play") +
#    theme(legend.position="none") +
    xlab("Play") +
    ylab("frequency of the word 'love'") +
    theme(legend.position = "none")

Attempting n-grams

library(dplyr)
#install.packages("tidytext")
library(tidytext)
shak %>%
  as_tibble(.) %>%
  unnest_tokens(tbl=., input = PlayerLine, output = word)
# A tibble: 820,204 x 6
   Dataline Play     PlayerLinenumber ActSceneLine Player word  
      <int> <chr>               <int> <chr>        <chr>  <chr> 
 1        1 Henry IV               NA ""           ""     act   
 2        1 Henry IV               NA ""           ""     i     
 3        2 Henry IV               NA ""           ""     scene 
 4        2 Henry IV               NA ""           ""     i     
 5        2 Henry IV               NA ""           ""     london
 6        2 Henry IV               NA ""           ""     the   
 7        2 Henry IV               NA ""           ""     palace
 8        3 Henry IV               NA ""           ""     enter 
 9        3 Henry IV               NA ""           ""     king  
10        3 Henry IV               NA ""           ""     henry 
# ... with 820,194 more rows
shak %>%
  as_tibble(.) %>%
  unnest_tokens(tbl=., input = PlayerLine, output = word) %>%
  count(word, sort = TRUE)
# A tibble: 24,749 x 2
   word      n
   <chr> <int>
 1 the   27052
 2 and   25082
 3 i     20142
 4 to    18984
 5 of    15862
 6 a     14196
 7 you   13347
 8 my    11875
 9 in    10540
10 that  10441
# ... with 24,739 more rows
shak %>%
  as_tibble(.) %>%
  unnest_tokens(tbl=., input = PlayerLine, output = word) %>%
  anti_join(stop_words) %>%
  count(word, sort = TRUE)
Joining, by = "word"
# A tibble: 24,148 x 2
   word      n
   <chr> <int>
 1 thou   5193
 2 thy    3727
 3 thee   3024
 4 lord   2621
 5 sir    2454
 6 enter  2338
 7 love   1927
 8 hath   1845
 9 king   1500
10 tis    1384
# ... with 24,138 more rows
shak %>%
  as_tibble(.) %>%
  unnest_tokens(tbl=., input = PlayerLine, output = word) %>%
  anti_join(stop_words) %>%
  count(word, sort = TRUE) %>%
  filter(n>800) %>%
  ggplot(., aes(x=reorder(word,n),y=n)) +
    geom_bar(stat="identity") +
    coord_flip()
Joining, by = "word"

Using tibbles

How can we organise this so that we can compare across plays?

shak[,c(2,5,6)] %>%
  as_tibble() %>%
  unnest_tokens(tbl=., input = PlayerLine, output = word) %>%
  filter(word=="love" | word =="king" | word=="death" | word=="sweet") %>%
  #add_count(Player) %>%
  group_by(Player,Play,word) %>%
  summarise(n=n()) %>%
  #anti_join(stop_words) %>%
  filter(  Play == "Hamlet" | 
           Play == "King Lear" | 
           Play == "A Midsummer nights dream" | 
           Play == "Othello" | 
           Play == "Henry V" | 
           Play == "Romeo and Juliet") %>%
  arrange(desc(n)) %>%
  ggplot(., aes(x=word,y=n)) +
    geom_bar(aes(fill=word),stat="identity") +
#    coord_flip() +
    facet_wrap(~Play)

Is there a way to break it down to see who is saying what?

What about n-grams

word <- c(NA,"thou","thee","thy","thine","dost","shalt","wilt","hast","hath","scene","tis","ii","iii","iv","v","vi","vii")
lexicon <- rep("shakespeare",length(word))
new_stop <- cbind(word,lexicon)
shak_stop <- rbind(new_stop,stop_words)
shak %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE)
# A tibble: 57,371 x 3
   word1    word2       n
   <chr>    <chr>   <int>
 1 enter    king      101
 2 mine     eyes       95
 3 king     henry      88
 4 sir      john       80
 5 mark     antony     76
 6 mine     honour     71
 7 king     richard    51
 8 god      save       48
 9 gracious lord       46
10 noble    lord       46
# ... with 57,361 more rows

Networks

#install.packages("igraph")
#install.packages("ggraph")
library(igraph)
library(ggraph)
library(grid)

Bigrams

set.seed(814)
a <- grid::arrow(type = "closed", angle=22.5, length = unit(.1, "inches"))
p1 <- shak %>%
  filter(Play=="Hamlet") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 6) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="darkblue", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "lightblue", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void()
set.seed(814)
p2 <- shak %>%
  filter(Play == "Twelfth Night") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 6) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="darkred", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "salmon", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void()
set.seed(814)
p3 <- shak %>%
  filter(Play == "Romeo and Juliet") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 6) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="darkgreen", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "green2", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void()
multiplot(p1,p2,p3,cols=3)

set.seed(814)
a <- grid::arrow(type = "closed", angle=22.5, length = unit(.1, "inches"))
p1 <- shak %>%
  filter(ActSceneLine != "") %>%
  filter(Play=="Hamlet") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 3) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="darkblue", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "lightblue", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void() +
    ggtitle("Hamlet")
set.seed(814)
p2 <- shak %>%
  filter(ActSceneLine != "") %>%
  filter(Play == "Twelfth Night") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 3) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="darkred", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "salmon", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void() +
    ggtitle("Twelfth Night")
set.seed(814)
p3 <- shak %>%
  filter(ActSceneLine != "") %>%
  filter(Play == "Romeo and Juliet") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 3) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="darkgreen", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "green2", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void() +
    ggtitle("Romeo and Juliet")
set.seed(814)
p4 <- shak %>%
  filter(ActSceneLine != "") %>%
  filter(Play == "Othello") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 3) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="darkorange", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "orange", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void() +
    ggtitle("Othello")
set.seed(814)
p5 <- shak %>%
  filter(ActSceneLine != "") %>%
  filter(Play == "Henry IV") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 3) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="cadetblue4", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "cyan", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void() +
    ggtitle("Henry IV")
set.seed(814)
p6 <- shak %>%
  filter(ActSceneLine != "") %>%
  filter(Play == "The Tempest") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 3) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="violet", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "magenta", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void() +
    ggtitle("The Tempest")
multiplot(p1,p2,p3,p4,p5,p6,cols=3)

Trigrams

This should give us a better idea of slightly looser connections

set.seed(814)
a <- grid::arrow(type = "closed", angle=22.5, length = unit(.1, "inches"))
shak %>%
  as_tibble() %>%
  filter(ActSceneLine != "") %>%
  unnest_tokens(input = PlayerLine, output = trigram, token = "ngrams", n = 3) %>%
  separate(trigram, c("word1", "word2", "word3"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  filter(!word3 %in% shak_stop$word) %>% # filters stop words from third column
  count(word1, word2, word3, sort = TRUE) %>%
  filter(n > 2) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="darkblue", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "lightblue", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void()

What happens if we treat the first pair and second pair of trigrams as separate bigrams and graph them as before?

Heatmaps

shak %>%
  as_tibble() %>%
  #filter(Play == "Hamlet" | Play == "Loves Labours Lost" | Play == "A Winters Tale") %>%
  filter(ActSceneLine != "") %>%
  mutate(ActSceneLine2 = ActSceneLine) %>%
  separate(ActSceneLine2, c("act", "scene", "line")) %>%
  count(Play,act,scene, sort=TRUE) %>%
  transmute(play=Play, act=as.numeric(act), scene=as.numeric(scene), n=n)
# A tibble: 737 x 4
   play                  act scene     n
   <chr>               <dbl> <dbl> <int>
 1 Loves Labours Lost      5     2   972
 2 A Winters Tale          4     4   929
 3 Hamlet                  2     2   616
 4 King John               2     1   609
 5 The Tempest             1     2   596
 6 Cymbeline               5     5   584
 7 Measure for measure     5     1   580
 8 Timon of Athens         4     3   577
 9 Richard III             4     4   561
10 A Winters Tale          1     2   539
# ... with 727 more rows

Wrap up

What this all seems to tell us is that we can visualise the structure of the play, separate from their content. Is this useful to you?

LS0tCnRpdGxlOiAiUHJvY2Vzc2luZyBTaGFrZXNwZWFyZSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAyCiAgICB0b2NfZmxvYXQ6IHllcwotLS0KCmBgYHtyIGVjaG89RkFMU0UsbWVzc2FnZT1GQUxTRX0KIyBNdWx0aXBsZSBwbG90IGZ1bmN0aW9uCiMKIyBnZ3Bsb3Qgb2JqZWN0cyBjYW4gYmUgcGFzc2VkIGluIC4uLiwgb3IgdG8gcGxvdGxpc3QgKGFzIGEgbGlzdCBvZiBnZ3Bsb3Qgb2JqZWN0cykKIyAtIGNvbHM6ICAgTnVtYmVyIG9mIGNvbHVtbnMgaW4gbGF5b3V0CiMgLSBsYXlvdXQ6IEEgbWF0cml4IHNwZWNpZnlpbmcgdGhlIGxheW91dC4gSWYgcHJlc2VudCwgJ2NvbHMnIGlzIGlnbm9yZWQuCiMKIyBJZiB0aGUgbGF5b3V0IGlzIHNvbWV0aGluZyBsaWtlIG1hdHJpeChjKDEsMiwzLDMpLCBucm93PTIsIGJ5cm93PVRSVUUpLAojIHRoZW4gcGxvdCAxIHdpbGwgZ28gaW4gdGhlIHVwcGVyIGxlZnQsIDIgd2lsbCBnbyBpbiB0aGUgdXBwZXIgcmlnaHQsIGFuZAojIDMgd2lsbCBnbyBhbGwgdGhlIHdheSBhY3Jvc3MgdGhlIGJvdHRvbS4KIwptdWx0aXBsb3QgPC0gZnVuY3Rpb24oLi4uLCBwbG90bGlzdD1OVUxMLCBmaWxlLCBjb2xzPTEsIGxheW91dD1OVUxMKSB7CiAgbGlicmFyeShncmlkKQoKICAjIE1ha2UgYSBsaXN0IGZyb20gdGhlIC4uLiBhcmd1bWVudHMgYW5kIHBsb3RsaXN0CiAgcGxvdHMgPC0gYyhsaXN0KC4uLiksIHBsb3RsaXN0KQoKICBudW1QbG90cyA9IGxlbmd0aChwbG90cykKCiAgIyBJZiBsYXlvdXQgaXMgTlVMTCwgdGhlbiB1c2UgJ2NvbHMnIHRvIGRldGVybWluZSBsYXlvdXQKICBpZiAoaXMubnVsbChsYXlvdXQpKSB7CiAgICAjIE1ha2UgdGhlIHBhbmVsCiAgICAjIG5jb2w6IE51bWJlciBvZiBjb2x1bW5zIG9mIHBsb3RzCiAgICAjIG5yb3c6IE51bWJlciBvZiByb3dzIG5lZWRlZCwgY2FsY3VsYXRlZCBmcm9tICMgb2YgY29scwogICAgbGF5b3V0IDwtIG1hdHJpeChzZXEoMSwgY29scyAqIGNlaWxpbmcobnVtUGxvdHMvY29scykpLAogICAgICAgICAgICAgICAgICAgIG5jb2wgPSBjb2xzLCBucm93ID0gY2VpbGluZyhudW1QbG90cy9jb2xzKSkKICB9CgogaWYgKG51bVBsb3RzPT0xKSB7CiAgICBwcmludChwbG90c1tbMV1dKQoKICB9IGVsc2UgewogICAgIyBTZXQgdXAgdGhlIHBhZ2UKICAgIGdyaWQubmV3cGFnZSgpCiAgICBwdXNoVmlld3BvcnQodmlld3BvcnQobGF5b3V0ID0gZ3JpZC5sYXlvdXQobnJvdyhsYXlvdXQpLCBuY29sKGxheW91dCkpKSkKCiAgICAjIE1ha2UgZWFjaCBwbG90LCBpbiB0aGUgY29ycmVjdCBsb2NhdGlvbgogICAgZm9yIChpIGluIDE6bnVtUGxvdHMpIHsKICAgICAgIyBHZXQgdGhlIGksaiBtYXRyaXggcG9zaXRpb25zIG9mIHRoZSByZWdpb25zIHRoYXQgY29udGFpbiB0aGlzIHN1YnBsb3QKICAgICAgbWF0Y2hpZHggPC0gYXMuZGF0YS5mcmFtZSh3aGljaChsYXlvdXQgPT0gaSwgYXJyLmluZCA9IFRSVUUpKQoKICAgICAgcHJpbnQocGxvdHNbW2ldXSwgdnAgPSB2aWV3cG9ydChsYXlvdXQucG9zLnJvdyA9IG1hdGNoaWR4JHJvdywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXlvdXQucG9zLmNvbCA9IG1hdGNoaWR4JGNvbCkpCiAgICB9CiAgfQp9CmBgYAoKCmBgYHtyLG1lc3NhZ2U9RkFMU0V9CiMgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIsImRwbHlyIikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpgYGAKCgojIFJlYWRpbmcgaW4gY29ycHVzCgpgYGB7cn0KIyBSIG11c3QgYmUgYXQgbGVhc3QgMy4zLjEgZm9yIGB0bWAgYW5kIGBzbGFtYCB0byB3b3JrLgojIGluc3RhbGwucGFja2FnZXMoInRtIikKIyBpbnN0YWxsLnBhY2thZ2VzKCJTbm93YmFsbEMiKQpsaWJyYXJ5KHRtKQojc3lzdGVtKCJscyAuLi9pbnB1dCIpICMgZG8gd2UgbmVlZCB0aGlzPwpgYGAKCgpBZGFwdGVkIGZyb20gW3RoaXMgS2FnZ2xlIG5vdGVib29rXShodHRwczovL3d3dy5rYWdnbGUuY29tL3NpbmRodWVlL2xvdmUtaW4tc2hha2VzcGVhcmU/c2NyaXB0VmVyc2lvbklkPTExMjEyNzApLgoKYGBge3J9CnNoYWs8LXJlYWQuY3N2KCIuLi9kYXRhL1NoYWtlc3BlYXJlX2RhdGEuY3N2IixoZWFkZXIgPSBUUlVFLCBhcy5pcyA9IFRSVUUpCiNzaGFrPC1uYS5vbWl0KHNoYWspCmhlYWQoc2hhaykKYGBgCgoKIyBXb3JkIGZyZXF1ZW5jeQoKYGBge3J9CiMgcGxheSBsZXZlbCB3b3JkIGZyZXF1ZW5jeQpwbGF5cyA8LSB1bmlxdWUoc2hhayRQbGF5KQpsb3ZlRnJlcTwtbnVtZXJpYygpCgpmb3IgKGkgaW4gMTpsZW5ndGgocGxheXMpKXsKICAgIHRleHQgPC0gQ29ycHVzKFZlY3RvclNvdXJjZShwYXN0ZShzaGFrW3NoYWskUGxheT09cGxheXNbaV0sXSRQbGF5ZXJMaW5lLGNvbGxhcHNlPSIgIikpKQogICAgdGV4dCA8LSB0bV9tYXAodGV4dCwgcmVtb3ZlUHVuY3R1YXRpb24pCiAgICB0ZXh0IDwtIHRtX21hcCh0ZXh0LCBQbGFpblRleHREb2N1bWVudCkKICAgIHRleHQgPC0gdG1fbWFwKHRleHQsIHJlbW92ZVdvcmRzLCBzdG9wd29yZHMoJ2VuZ2xpc2gnKSkKICAgIAogICAgIyBzdGVtbWluZyB0byBtZXJnZSBhbGwgImxvdmVkIiwgImxvdmluZyIgaW50byBvbmUgICAKICAgIHRleHQgPC0gdG1fbWFwKHRleHQsIHN0ZW1Eb2N1bWVudCkKICAgIHRkbSAgPC0gVGVybURvY3VtZW50TWF0cml4KHRleHQpCiAgICAKICAgIGxvdmVGcmVxW2ldPC1hcy5udW1lcmljKHNsYW06OnJvd19zdW1zKHRkbSlbImxvdmUiXSkKICB9CgpsUGxheSA8LSBkYXRhLmZyYW1lKHBsYXlzLGxvdmVGcmVxKQpsUGxheSA8LSBuYS5vbWl0KGxQbGF5KQoKIyBvcmRlciB0aGUgcGxheXMgYmFzZWQgb24gdGhlIG9jY3VyZW5jZSBvZiBsb3ZlCmxQbGF5PC1sUGxheVtvcmRlcigtbFBsYXkkbG92ZUZyZXEpLF0KaGVhZChsUGxheSkKYGBgCgpgYGB7cn0KIyBwbGF5ZXIgbGV2ZWwgd29yZCBmcmVxdWVuY3kKcGxheWVycyA8LSB1bmlxdWUoc2hhayRQbGF5ZXIpCmxvdmVGcmVxIDwtIG51bWVyaWMoKQoKZm9yIChpIGluIDE6bGVuZ3RoKHBsYXllcnMpKXsKICAgIHRleHQgPC0gQ29ycHVzKFZlY3RvclNvdXJjZShwYXN0ZShzaGFrW3NoYWskUGxheWVyPT1wbGF5ZXJzW2ldLF0kUGxheWVyTGluZSxjb2xsYXBzZT0iICIpKSkKICAgIHRleHQgPC0gdG1fbWFwKHRleHQsIHJlbW92ZVB1bmN0dWF0aW9uKQogICAgdGV4dCA8LSB0bV9tYXAodGV4dCwgUGxhaW5UZXh0RG9jdW1lbnQpCiAgICB0ZXh0IDwtIHRtX21hcCh0ZXh0LCByZW1vdmVXb3Jkcywgc3RvcHdvcmRzKCdlbmdsaXNoJykpCiAgICB0ZXh0IDwtIHRtX21hcCh0ZXh0LHN0ZW1Eb2N1bWVudCkKICAgIAogICAgdGRtICA8LSBUZXJtRG9jdW1lbnRNYXRyaXgodGV4dCkKICAgIAogICAgbG92ZUZyZXFbaV0gPC0gYXMubnVtZXJpYyhzbGFtOjpyb3dfc3Vtcyh0ZG0pWyJsb3ZlIl0pCiAgfQoKbFBsYXllciA8LSBkYXRhLmZyYW1lKHBsYXllcnMsbG92ZUZyZXEpCmxQbGF5ZXIgPC0gbmEub21pdChsUGxheWVyKQojb3JkZXIKbFBsYXllciA8LSBsUGxheWVyW29yZGVyKC1sUGxheWVyJGxvdmVGcmVxKSxdCgpoZWFkKGxQbGF5ZXIpCmBgYAoKIyBWaXN1YWxpc2luZyBjb3JwdXMKCmBgYHtyfQpzaGFrICU+JQogIGdyb3VwX2J5KFBsYXkpICU+JQogIHN1bW1hcmlzZShuID0gbigpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHg9cmVvcmRlcihQbGF5LCBuKSx5PW4pKSArCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsKICAgIGNvb3JkX2ZsaXAoKSArCiAgICBnZ3RpdGxlKCJMZW5ndGggb2YgU2hha2VzcGVhcmUncyBwbGF5cyIpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICAgIHhsYWIoIlBsYXkiKSArCiAgICB5bGFiKCJOdW1iZXIgb2YgbGluZXMiKQpgYGAKCmBgYHtyfQpzaGFrICU+JQogIGZpbHRlcihQbGF5ID09ICJIYW1sZXQiKSAlPiUKICBncm91cF9ieShQbGF5ZXIpICU+JQogIHN1bW1hcmlzZShuID0gbigpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHg9cmVvcmRlcihQbGF5ZXIsIG4pLHk9bikpICsKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikgKwogICAgY29vcmRfZmxpcCgpICsKICAgIGdndGl0bGUoIlNwZWVjaCBpbiBIYW1sZXQiKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiAgICB4bGFiKCJQbGF5ZXIiKSArCiAgICB5bGFiKCJOdW1iZXIgb2YgbGluZXMiKQpgYGAKCmBgYHtyfQpzaGFrICU+JQogIGdyb3VwX2J5KFBsYXksUGxheWVyKSAlPiUKICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lCiAgZmlsdGVyKG4gPiA3MDApICU+JQogIGdncGxvdCguLCBhZXMoeD1yZW9yZGVyKFBsYXllciwgbikseT1uKSkgKwogICAgZ2VvbV9iYXIoYWVzKGZpbGw9UGxheSksc3RhdD0iaWRlbnRpdHkiKSArCiAgICBjb29yZF9mbGlwKCkgKwogICAgZ2d0aXRsZSgiQW1vdW50IG9mIGxpbmVzIGJ5IGNoYXJhY3RlciIpICsKIyAgICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiAgICB4bGFiKCJQbGF5ZXIiKSArCiAgICB5bGFiKCJOdW1iZXIgb2YgbGluZXMiKQpgYGAKCmBgYHtyfQpsUGxheSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHg9cmVvcmRlcihwbGF5cywgbG92ZUZyZXEpLHk9bG92ZUZyZXEpKSArCiAgICBnZW9tX2JhcihhZXMoZmlsbD1wbGF5cyksc3RhdD0iaWRlbnRpdHkiKSArCiAgICBjb29yZF9mbGlwKCkgKwogICAgZ2d0aXRsZSgiTG92ZSBpbiBlYWNoIHBsYXkiKSArCiMgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogICAgeGxhYigiUGxheSIpICsKICAgIHlsYWIoImZyZXF1ZW5jeSBvZiB0aGUgd29yZCAnbG92ZSciKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKYGBge3J9CmxQbGF5ZXIgJT4lCiAgZmlsdGVyKGxvdmVGcmVxID4gMjApICU+JQogIGdncGxvdCguLCBhZXMoeD1yZW9yZGVyKHBsYXllcnMsIGxvdmVGcmVxKSx5PWxvdmVGcmVxKSkgKwogICAgZ2VvbV9iYXIoYWVzKGZpbGw9cGxheWVycyksc3RhdD0iaWRlbnRpdHkiKSArCiAgICBjb29yZF9mbGlwKCkgKwogICAgZ2d0aXRsZSgiTG92ZSBpbiBlYWNoIHBsYXkiKSArCiMgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogICAgeGxhYigiUGxheSIpICsKICAgIHlsYWIoImZyZXF1ZW5jeSBvZiB0aGUgd29yZCAnbG92ZSciKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKIyBBdHRlbXB0aW5nIG4tZ3JhbXMKCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQojaW5zdGFsbC5wYWNrYWdlcygidGlkeXRleHQiKQpsaWJyYXJ5KHRpZHl0ZXh0KQpgYGAKCgpgYGB7cn0Kc2hhayAlPiUKICBhc190aWJibGUoLikgJT4lCiAgdW5uZXN0X3Rva2Vucyh0Ymw9LiwgaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSB3b3JkKQpgYGAKCmBgYHtyfQpzaGFrICU+JQogIGFzX3RpYmJsZSguKSAlPiUKICB1bm5lc3RfdG9rZW5zKHRibD0uLCBpbnB1dCA9IFBsYXllckxpbmUsIG91dHB1dCA9IHdvcmQpICU+JQogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKQpgYGAKCmBgYHtyfQpzaGFrICU+JQogIGFzX3RpYmJsZSguKSAlPiUKICB1bm5lc3RfdG9rZW5zKHRibD0uLCBpbnB1dCA9IFBsYXllckxpbmUsIG91dHB1dCA9IHdvcmQpICU+JQogIGFudGlfam9pbihzdG9wX3dvcmRzKSAlPiUKICBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkKYGBgCgpgYGB7cn0Kc2hhayAlPiUKICBhc190aWJibGUoLikgJT4lCiAgdW5uZXN0X3Rva2Vucyh0Ymw9LiwgaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSB3b3JkKSAlPiUKICBhbnRpX2pvaW4oc3RvcF93b3JkcykgJT4lCiAgY291bnQod29yZCwgc29ydCA9IFRSVUUpICU+JQogIGZpbHRlcihuPjgwMCkgJT4lCiAgZ2dwbG90KC4sIGFlcyh4PXJlb3JkZXIod29yZCxuKSx5PW4pKSArCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsKICAgIGNvb3JkX2ZsaXAoKQpgYGAKCiMjIFVzaW5nIHRpYmJsZXMKCkhvdyBjYW4gd2Ugb3JnYW5pc2UgdGhpcyBzbyB0aGF0IHdlIGNhbiBjb21wYXJlIGFjcm9zcyBwbGF5cz8KCmBgYHtyfQpzaGFrWyxjKDIsNSw2KV0gJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgdW5uZXN0X3Rva2Vucyh0Ymw9LiwgaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSB3b3JkKSAlPiUKICBmaWx0ZXIod29yZD09ImxvdmUiIHwgd29yZCA9PSJraW5nIiB8IHdvcmQ9PSJkZWF0aCIgfCB3b3JkPT0ic3dlZXQiKSAlPiUKICAjYWRkX2NvdW50KFBsYXllcikgJT4lCiAgZ3JvdXBfYnkoUGxheWVyLFBsYXksd29yZCkgJT4lCiAgc3VtbWFyaXNlKG49bigpKSAlPiUKICAjYW50aV9qb2luKHN0b3Bfd29yZHMpICU+JQogIGZpbHRlciggIFBsYXkgPT0gIkhhbWxldCIgfCAKICAgICAgICAgICBQbGF5ID09ICJLaW5nIExlYXIiIHwgCiAgICAgICAgICAgUGxheSA9PSAiQSBNaWRzdW1tZXIgbmlnaHRzIGRyZWFtIiB8IAogICAgICAgICAgIFBsYXkgPT0gIk90aGVsbG8iIHwgCiAgICAgICAgICAgUGxheSA9PSAiSGVucnkgViIgfCAKICAgICAgICAgICBQbGF5ID09ICJSb21lbyBhbmQgSnVsaWV0IikgJT4lCiAgYXJyYW5nZShkZXNjKG4pKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHg9d29yZCx5PW4pKSArCiAgICBnZW9tX2JhcihhZXMoZmlsbD13b3JkKSxzdGF0PSJpZGVudGl0eSIpICsKIyAgICBjb29yZF9mbGlwKCkgKwogICAgZmFjZXRfd3JhcCh+UGxheSkKYGBgCgpJcyB0aGVyZSBhIHdheSB0byBicmVhayBpdCBkb3duIHRvIHNlZSB3aG8gaXMgc2F5aW5nIHdoYXQ/CgojIyBXaGF0IGFib3V0IG4tZ3JhbXMKCmBgYHtyIGZpZy53aWR0aD01LCBmaWcuYXNwPS41fQoKc2hhayAlPiUKICBhc190aWJibGUoKSAlPiUKICB1bm5lc3RfdG9rZW5zKGlucHV0ID0gUGxheWVyTGluZSwgb3V0cHV0ID0gYmlncmFtLCB0b2tlbiA9ICJuZ3JhbXMiLCBuID0gMikgJT4lCiAgI2FudGlfam9pbihzdG9wX3dvcmRzKSAlPiUKICBmaWx0ZXIoYmlncmFtPT0ibXkgbG9yZCIgfCBiaWdyYW0gPT0ibXkgbGFkeSIgfCBiaWdyYW09PSJteSBtb3RoZXIiIHwgYmlncmFtPT0ibXkgZmF0aGVyIiB8IGJpZ3JhbT09Im15IHdpZmUiIHwgYmlncmFtPT0ibXkgaHVzYmFuZCIpICU+JQogIG11dGF0ZShnZW5kZXIgPSBiaWdyYW0pICU+JQogIG11dGF0ZShnZW5kZXIgPSByZWNvZGVfZmFjdG9yKGdlbmRlciwKICAgICAgICAgICAgICAgIGBteSBsb3JkYD0ibWFzYyIsCiAgICAgICAgICAgICAgICBgbXkgZmF0aGVyYD0ibWFzYyIsCiAgICAgICAgICAgICAgICBgbXkgaHVzYmFuZGA9Im1hc2MiLAogICAgICAgICAgICAgICAgYG15IGxhZHlgPSJmZW0iLAogICAgICAgICAgICAgICAgYG15IG1vdGhlcmA9ImZlbSIsCiAgICAgICAgICAgICAgICBgbXkgd2lmZWA9ImZlbSIpKSAlPiUKICBncm91cF9ieShQbGF5ZXIsUGxheSxiaWdyYW0sZ2VuZGVyKSAlPiUKICBzdW1tYXJpc2Uobj1uKCkpICU+JQogIG11dGF0ZShiaWdyYW1GYWMgPSBmYWN0b3IoYmlncmFtLCBsZXZlbHM9YygibXkgbG9yZCIsICJteSBodXNiYW5kIiwgIm15IGZhdGhlciIsICJteSBsYWR5IiwgIm15IHdpZmUiLCAibXkgbW90aGVyIikpKSAlPiUKICAjIHRvbyBib3JpbmcKICBmaWx0ZXIoICBQbGF5ICE9ICJIZW5yeSBWSSBQYXJ0IDEiICYKICAgICAgICAgICBQbGF5ICE9ICJIZW5yeSBWSSBQYXJ0IDIiICYKICAgICAgICAgICBQbGF5ICE9ICJIZW5yeSBWSSBQYXJ0IDMiICYKICAgICAgICAgICBQbGF5ICE9ICJQZXJpY2xlcyIgJiAKICAgICAgICAgICBQbGF5ICE9ICJUaW1vbiBvZiBBdGhlbnMiICYgCiAgICAgICAgICAgUGxheSAhPSAiVGhlIFRlbXBlc3QiKSAlPiUKICAjIHRvbyBza2V3ZWQKICBmaWx0ZXIoICBQbGF5ICE9ICJIYW1sZXQiICYKICAgICAgICAgICBQbGF5ICE9ICJUcm9pbHVzIGFuZCBDcmVzc2lkYSIgJgogICAgICAgICAgIFBsYXkgIT0gIlJpY2hhcmQgSUlJIiAmCiAgICAgICAgICAgUGxheSAhPSAiVGl0dXMgQW5kcm9uaWN1cyIgJiAKICAgICAgICAgICBQbGF5ICE9ICJIZW5yeSBWSUlJIiAmIAogICAgICAgICAgIFBsYXkgIT0gIk11Y2ggQWRvIGFib3V0IG5vdGhpbmciKSAlPiUKICBhcnJhbmdlKGRlc2MobikpICU+JQogIGdncGxvdCguLCBhZXMoeD1iaWdyYW1GYWMseT1uKSkgKwogICAgZ2VvbV9iYXIoYWVzKGZpbGw9Z2VuZGVyKSxzdGF0PSJpZGVudGl0eSIpKyMscG9zaXRpb249ImRvZGdlIikgKwogICAgc2NhbGVfeV9sb2cxMCgpICsKICAgIGNvb3JkX2ZsaXAoKSArCiAgICBmYWNldF93cmFwKH5QbGF5LG5yb3c9MykKYGBgCgpgYGB7cn0Kc2hhayAlPiUKICBhc190aWJibGUoKSAlPiUKICB1bm5lc3RfdG9rZW5zKGlucHV0ID0gUGxheWVyTGluZSwgb3V0cHV0ID0gbmdyYW0sIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUKICBtdXRhdGUoYmlncmFtID0gbmdyYW0pICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBuZ3JhbSwgb3V0cHV0ID0gd29yZCkgJT4lCiAgI2FudGlfam9pbihzdG9wX3dvcmRzKSAlPiUKICBmaWx0ZXIod29yZD09ImtpbmciIHwgd29yZD09InF1ZWVuIikgJT4lCiAgZ3JvdXBfYnkoUGxheSxiaWdyYW0sd29yZCkgJT4lCiAgc3VtbWFyaXNlKG49bigpKSAlPiUKICBhcnJhbmdlKGRlc2MobikpICU+JQogIGdncGxvdChhZXMoeD1yZW9yZGVyKFBsYXksbikpKSArCiAgICBnZW9tX2JhcihhZXMoZmlsbD13b3JkKSxzdGF0PSJjb3VudCIscG9zaXRpb249ImRvZGdlIikgKwogICAgI3NjYWxlX3lfbG9nMTAoKSArCiAgICBjb29yZF9mbGlwKCkKYGBgCgoKYGBge3J9CndvcmQgPC0gYyhOQSwidGhvdSIsInRoZWUiLCJ0aHkiLCJ0aGluZSIsImRvc3QiLCJzaGFsdCIsIndpbHQiLCJoYXN0IiwiaGF0aCIsInNjZW5lIiwidGlzIiwiaWkiLCJpaWkiLCJpdiIsInYiLCJ2aSIsInZpaSIpCmxleGljb24gPC0gcmVwKCJzaGFrZXNwZWFyZSIsbGVuZ3RoKHdvcmQpKQpuZXdfc3RvcCA8LSBjYmluZCh3b3JkLGxleGljb24pCnNoYWtfc3RvcCA8LSByYmluZChuZXdfc3RvcCxzdG9wX3dvcmRzKQpgYGAKCgoKYGBge3J9CnNoYWsgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgdW5uZXN0X3Rva2VucyhpbnB1dCA9IFBsYXllckxpbmUsIG91dHB1dCA9IGJpZ3JhbSwgdG9rZW4gPSAibmdyYW1zIiwgbiA9IDIpICU+JQogIHNlcGFyYXRlKGJpZ3JhbSwgYygid29yZDEiLCAid29yZDIiKSwgc2VwID0gIiAiKSAlPiUgIyBzZXBhcmF0ZXMgYmlncmFtIGludG8gdHdvIGNvbHVtbnMsIG9uZSBmb3IgZWFjaCB3b3JkCiAgZmlsdGVyKCF3b3JkMSAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBmaXJzdCBjb2x1bW4KICBmaWx0ZXIoIXdvcmQyICVpbiUgc2hha19zdG9wJHdvcmQpICU+JSAjIGZpbHRlcnMgc3RvcCB3b3JkcyBmcm9tIHNlY29uZCBjb2x1bW4KICBjb3VudCh3b3JkMSwgd29yZDIsIHNvcnQgPSBUUlVFKQpgYGAKCiMjIE5ldHdvcmtzCgpgYGB7cn0KI2luc3RhbGwucGFja2FnZXMoImlncmFwaCIpCiNpbnN0YWxsLnBhY2thZ2VzKCJnZ3JhcGgiKQpsaWJyYXJ5KGlncmFwaCkKbGlicmFyeShnZ3JhcGgpCmxpYnJhcnkoZ3JpZCkKYGBgCgojIyMgQmlncmFtcwoKYGBge3J9CnNldC5zZWVkKDgxNCkKYSA8LSBncmlkOjphcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlPTIyLjUsIGxlbmd0aCA9IHVuaXQoLjEsICJpbmNoZXMiKSkKc2hhayAlPiUKICBhc190aWJibGUoKSAlPiUKICB1bm5lc3RfdG9rZW5zKGlucHV0ID0gUGxheWVyTGluZSwgb3V0cHV0ID0gYmlncmFtLCB0b2tlbiA9ICJuZ3JhbXMiLCBuID0gMikgJT4lCiAgc2VwYXJhdGUoYmlncmFtLCBjKCJ3b3JkMSIsICJ3b3JkMiIpLCBzZXAgPSAiICIpICU+JSAjIHNlcGFyYXRlcyBiaWdyYW0gaW50byB0d28gY29sdW1ucywgb25lIGZvciBlYWNoIHdvcmQKICBmaWx0ZXIoIXdvcmQxICVpbiUgc2hha19zdG9wJHdvcmQpICU+JSAjIGZpbHRlcnMgc3RvcCB3b3JkcyBmcm9tIGZpcnN0IGNvbHVtbgogIGZpbHRlcighd29yZDIgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gc2Vjb25kIGNvbHVtbgogIGNvdW50KHdvcmQxLCB3b3JkMiwgc29ydCA9IFRSVUUpICU+JQogIGZpbHRlcihuID4gMjIpICU+JQogIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSgpICU+JQogIGdncmFwaChsYXlvdXQgPSAiZnIiKSArCiAgICBnZW9tX2VkZ2VfbGluayhhZXMoZWRnZV9hbHBoYSA9IG4pLCBlZGdlX2NvbG91cj0iZGFya2JsdWUiLCBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgICAgICAgIGFycm93ID0gYSwgZW5kX2NhcCA9IGNpcmNsZSguMDcsICdpbmNoZXMnKSkgKwogICAgZ2VvbV9ub2RlX3BvaW50KGNvbG9yID0gImxpZ2h0Ymx1ZSIsIHNpemUgPSA1KSArCiAgICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgcmVwZWw9VFJVRSkgKyAjICwgdmp1c3QgPSAxLCBoanVzdCA9IDEpICsKICAgIHRoZW1lX3ZvaWQoKQpgYGAKCgoKYGBge3J9CnNldC5zZWVkKDgxNCkKYSA8LSBncmlkOjphcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlPTIyLjUsIGxlbmd0aCA9IHVuaXQoLjEsICJpbmNoZXMiKSkKcDEgPC0gc2hhayAlPiUKICBmaWx0ZXIoUGxheT09IkhhbWxldCIpICU+JQogIGFzX3RpYmJsZSgpICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSBiaWdyYW0sIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkgJT4lCiAgZmlsdGVyKG4gPiA2KSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgZWRnZV9jb2xvdXI9ImRhcmtibHVlIiwgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICBhcnJvdyA9IGEsIGVuZF9jYXAgPSBjaXJjbGUoLjA3LCAnaW5jaGVzJykpICsKICAgIGdlb21fbm9kZV9wb2ludChjb2xvciA9ICJsaWdodGJsdWUiLCBzaXplID0gNSkgKwogICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHJlcGVsPVRSVUUpICsgIyAsIHZqdXN0ID0gMSwgaGp1c3QgPSAxKSArCiAgICB0aGVtZV92b2lkKCkKCnNldC5zZWVkKDgxNCkKcDIgPC0gc2hhayAlPiUKICBmaWx0ZXIoUGxheSA9PSAiVHdlbGZ0aCBOaWdodCIpICU+JQogIGFzX3RpYmJsZSgpICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSBiaWdyYW0sIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkgJT4lCiAgZmlsdGVyKG4gPiA2KSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgZWRnZV9jb2xvdXI9ImRhcmtyZWQiLCBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgICAgICAgIGFycm93ID0gYSwgZW5kX2NhcCA9IGNpcmNsZSguMDcsICdpbmNoZXMnKSkgKwogICAgZ2VvbV9ub2RlX3BvaW50KGNvbG9yID0gInNhbG1vbiIsIHNpemUgPSA1KSArCiAgICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgcmVwZWw9VFJVRSkgKyAjICwgdmp1c3QgPSAxLCBoanVzdCA9IDEpICsKICAgIHRoZW1lX3ZvaWQoKQoKc2V0LnNlZWQoODE0KQpwMyA8LSBzaGFrICU+JQogIGZpbHRlcihQbGF5ID09ICJSb21lbyBhbmQgSnVsaWV0IikgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgdW5uZXN0X3Rva2VucyhpbnB1dCA9IFBsYXllckxpbmUsIG91dHB1dCA9IGJpZ3JhbSwgdG9rZW4gPSAibmdyYW1zIiwgbiA9IDIpICU+JQogIHNlcGFyYXRlKGJpZ3JhbSwgYygid29yZDEiLCAid29yZDIiKSwgc2VwID0gIiAiKSAlPiUgIyBzZXBhcmF0ZXMgYmlncmFtIGludG8gdHdvIGNvbHVtbnMsIG9uZSBmb3IgZWFjaCB3b3JkCiAgZmlsdGVyKCF3b3JkMSAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBmaXJzdCBjb2x1bW4KICBmaWx0ZXIoIXdvcmQyICVpbiUgc2hha19zdG9wJHdvcmQpICU+JSAjIGZpbHRlcnMgc3RvcCB3b3JkcyBmcm9tIHNlY29uZCBjb2x1bW4KICBjb3VudCh3b3JkMSwgd29yZDIsIHNvcnQgPSBUUlVFKSAlPiUKICBmaWx0ZXIobiA+IDYpICU+JQogIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSgpICU+JQogIGdncmFwaChsYXlvdXQgPSAiZnIiKSArCiAgICBnZW9tX2VkZ2VfbGluayhhZXMoZWRnZV9hbHBoYSA9IG4pLCBlZGdlX2NvbG91cj0iZGFya2dyZWVuIiwgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICBhcnJvdyA9IGEsIGVuZF9jYXAgPSBjaXJjbGUoLjA3LCAnaW5jaGVzJykpICsKICAgIGdlb21fbm9kZV9wb2ludChjb2xvciA9ICJncmVlbjIiLCBzaXplID0gNSkgKwogICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHJlcGVsPVRSVUUpICsgIyAsIHZqdXN0ID0gMSwgaGp1c3QgPSAxKSArCiAgICB0aGVtZV92b2lkKCkKCm11bHRpcGxvdChwMSxwMixwMyxjb2xzPTMpCmBgYAoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5hc3A9LjV9CnNldC5zZWVkKDgxNCkKYSA8LSBncmlkOjphcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlPTIyLjUsIGxlbmd0aCA9IHVuaXQoLjEsICJpbmNoZXMiKSkKcDEgPC0gc2hhayAlPiUKICBmaWx0ZXIoQWN0U2NlbmVMaW5lICE9ICIiKSAlPiUKICBmaWx0ZXIoUGxheT09IkhhbWxldCIpICU+JQogIGFzX3RpYmJsZSgpICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSBiaWdyYW0sIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkgJT4lCiAgZmlsdGVyKG4gPiAzKSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgZWRnZV9jb2xvdXI9ImRhcmtibHVlIiwgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICBhcnJvdyA9IGEsIGVuZF9jYXAgPSBjaXJjbGUoLjA3LCAnaW5jaGVzJykpICsKICAgIGdlb21fbm9kZV9wb2ludChjb2xvciA9ICJsaWdodGJsdWUiLCBzaXplID0gNSkgKwogICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHJlcGVsPVRSVUUpICsgIyAsIHZqdXN0ID0gMSwgaGp1c3QgPSAxKSArCiAgICB0aGVtZV92b2lkKCkgKwogICAgZ2d0aXRsZSgiSGFtbGV0IikKCnNldC5zZWVkKDgxNCkKcDIgPC0gc2hhayAlPiUKICBmaWx0ZXIoQWN0U2NlbmVMaW5lICE9ICIiKSAlPiUKICBmaWx0ZXIoUGxheSA9PSAiVHdlbGZ0aCBOaWdodCIpICU+JQogIGFzX3RpYmJsZSgpICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSBiaWdyYW0sIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkgJT4lCiAgZmlsdGVyKG4gPiAzKSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgZWRnZV9jb2xvdXI9ImRhcmtyZWQiLCBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgICAgICAgIGFycm93ID0gYSwgZW5kX2NhcCA9IGNpcmNsZSguMDcsICdpbmNoZXMnKSkgKwogICAgZ2VvbV9ub2RlX3BvaW50KGNvbG9yID0gInNhbG1vbiIsIHNpemUgPSA1KSArCiAgICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgcmVwZWw9VFJVRSkgKyAjICwgdmp1c3QgPSAxLCBoanVzdCA9IDEpICsKICAgIHRoZW1lX3ZvaWQoKSArCiAgICBnZ3RpdGxlKCJUd2VsZnRoIE5pZ2h0IikKCnNldC5zZWVkKDgxNCkKcDMgPC0gc2hhayAlPiUKICBmaWx0ZXIoQWN0U2NlbmVMaW5lICE9ICIiKSAlPiUKICBmaWx0ZXIoUGxheSA9PSAiUm9tZW8gYW5kIEp1bGlldCIpICU+JQogIGFzX3RpYmJsZSgpICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSBiaWdyYW0sIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkgJT4lCiAgZmlsdGVyKG4gPiAzKSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgZWRnZV9jb2xvdXI9ImRhcmtncmVlbiIsIHNob3cubGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgYXJyb3cgPSBhLCBlbmRfY2FwID0gY2lyY2xlKC4wNywgJ2luY2hlcycpKSArCiAgICBnZW9tX25vZGVfcG9pbnQoY29sb3IgPSAiZ3JlZW4yIiwgc2l6ZSA9IDUpICsKICAgIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCByZXBlbD1UUlVFKSArICMgLCB2anVzdCA9IDEsIGhqdXN0ID0gMSkgKwogICAgdGhlbWVfdm9pZCgpICsKICAgIGdndGl0bGUoIlJvbWVvIGFuZCBKdWxpZXQiKQoKc2V0LnNlZWQoODE0KQpwNCA8LSBzaGFrICU+JQogIGZpbHRlcihBY3RTY2VuZUxpbmUgIT0gIiIpICU+JQogIGZpbHRlcihQbGF5ID09ICJPdGhlbGxvIikgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgdW5uZXN0X3Rva2VucyhpbnB1dCA9IFBsYXllckxpbmUsIG91dHB1dCA9IGJpZ3JhbSwgdG9rZW4gPSAibmdyYW1zIiwgbiA9IDIpICU+JQogIHNlcGFyYXRlKGJpZ3JhbSwgYygid29yZDEiLCAid29yZDIiKSwgc2VwID0gIiAiKSAlPiUgIyBzZXBhcmF0ZXMgYmlncmFtIGludG8gdHdvIGNvbHVtbnMsIG9uZSBmb3IgZWFjaCB3b3JkCiAgZmlsdGVyKCF3b3JkMSAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBmaXJzdCBjb2x1bW4KICBmaWx0ZXIoIXdvcmQyICVpbiUgc2hha19zdG9wJHdvcmQpICU+JSAjIGZpbHRlcnMgc3RvcCB3b3JkcyBmcm9tIHNlY29uZCBjb2x1bW4KICBjb3VudCh3b3JkMSwgd29yZDIsIHNvcnQgPSBUUlVFKSAlPiUKICBmaWx0ZXIobiA+IDMpICU+JQogIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSgpICU+JQogIGdncmFwaChsYXlvdXQgPSAiZnIiKSArCiAgICBnZW9tX2VkZ2VfbGluayhhZXMoZWRnZV9hbHBoYSA9IG4pLCBlZGdlX2NvbG91cj0iZGFya29yYW5nZSIsIHNob3cubGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgYXJyb3cgPSBhLCBlbmRfY2FwID0gY2lyY2xlKC4wNywgJ2luY2hlcycpKSArCiAgICBnZW9tX25vZGVfcG9pbnQoY29sb3IgPSAib3JhbmdlIiwgc2l6ZSA9IDUpICsKICAgIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCByZXBlbD1UUlVFKSArICMgLCB2anVzdCA9IDEsIGhqdXN0ID0gMSkgKwogICAgdGhlbWVfdm9pZCgpICsKICAgIGdndGl0bGUoIk90aGVsbG8iKQoKc2V0LnNlZWQoODE0KQpwNSA8LSBzaGFrICU+JQogIGZpbHRlcihBY3RTY2VuZUxpbmUgIT0gIiIpICU+JQogIGZpbHRlcihQbGF5ID09ICJIZW5yeSBJViIpICU+JQogIGFzX3RpYmJsZSgpICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSBiaWdyYW0sIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkgJT4lCiAgZmlsdGVyKG4gPiAzKSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgZWRnZV9jb2xvdXI9ImNhZGV0Ymx1ZTQiLCBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgICAgICAgIGFycm93ID0gYSwgZW5kX2NhcCA9IGNpcmNsZSguMDcsICdpbmNoZXMnKSkgKwogICAgZ2VvbV9ub2RlX3BvaW50KGNvbG9yID0gImN5YW4iLCBzaXplID0gNSkgKwogICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHJlcGVsPVRSVUUpICsgIyAsIHZqdXN0ID0gMSwgaGp1c3QgPSAxKSArCiAgICB0aGVtZV92b2lkKCkgKwogICAgZ2d0aXRsZSgiSGVucnkgSVYiKQoKc2V0LnNlZWQoODE0KQpwNiA8LSBzaGFrICU+JQogIGZpbHRlcihBY3RTY2VuZUxpbmUgIT0gIiIpICU+JQogIGZpbHRlcihQbGF5ID09ICJUaGUgVGVtcGVzdCIpICU+JQogIGFzX3RpYmJsZSgpICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSBiaWdyYW0sIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkgJT4lCiAgZmlsdGVyKG4gPiAzKSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgZWRnZV9jb2xvdXI9InZpb2xldCIsIHNob3cubGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgYXJyb3cgPSBhLCBlbmRfY2FwID0gY2lyY2xlKC4wNywgJ2luY2hlcycpKSArCiAgICBnZW9tX25vZGVfcG9pbnQoY29sb3IgPSAibWFnZW50YSIsIHNpemUgPSA1KSArCiAgICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgcmVwZWw9VFJVRSkgKyAjICwgdmp1c3QgPSAxLCBoanVzdCA9IDEpICsKICAgIHRoZW1lX3ZvaWQoKSArCiAgICBnZ3RpdGxlKCJUaGUgVGVtcGVzdCIpCgptdWx0aXBsb3QocDEscDIscDMscDQscDUscDYsY29scz0zKQpgYGAKCiMjIyBUcmlncmFtcwoKVGhpcyBzaG91bGQgZ2l2ZSB1cyBhIGJldHRlciBpZGVhIG9mIHNsaWdodGx5IGxvb3NlciBjb25uZWN0aW9ucwoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5hc3A9LjV9CnNldC5zZWVkKDgxNCkKYSA8LSBncmlkOjphcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlPTIyLjUsIGxlbmd0aCA9IHVuaXQoLjEsICJpbmNoZXMiKSkKc2hhayAlPiUKICBhc190aWJibGUoKSAlPiUKICBmaWx0ZXIoQWN0U2NlbmVMaW5lICE9ICIiKSAlPiUKICB1bm5lc3RfdG9rZW5zKGlucHV0ID0gUGxheWVyTGluZSwgb3V0cHV0ID0gdHJpZ3JhbSwgdG9rZW4gPSAibmdyYW1zIiwgbiA9IDMpICU+JQogIHNlcGFyYXRlKHRyaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiwgIndvcmQzIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgZmlsdGVyKCF3b3JkMyAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSB0aGlyZCBjb2x1bW4KICBjb3VudCh3b3JkMSwgd29yZDIsIHdvcmQzLCBzb3J0ID0gVFJVRSkgJT4lCiAgZmlsdGVyKG4gPiAyKSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgZWRnZV9jb2xvdXI9ImRhcmtibHVlIiwgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICBhcnJvdyA9IGEsIGVuZF9jYXAgPSBjaXJjbGUoLjA3LCAnaW5jaGVzJykpICsKICAgIGdlb21fbm9kZV9wb2ludChjb2xvciA9ICJsaWdodGJsdWUiLCBzaXplID0gNSkgKwogICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHJlcGVsPVRSVUUpICsgIyAsIHZqdXN0ID0gMSwgaGp1c3QgPSAxKSArCiAgICB0aGVtZV92b2lkKCkKYGBgCgoKV2hhdCBoYXBwZW5zIGlmIHdlIHRyZWF0IHRoZSBmaXJzdCBwYWlyIGFuZCBzZWNvbmQgcGFpciBvZiB0cmlncmFtcyBhcyBzZXBhcmF0ZSBiaWdyYW1zIGFuZCBncmFwaCB0aGVtIGFzIGJlZm9yZT8KCmBgYHtyIGZpZy53aWR0aD01LCBmaWcuYXNwPS43NX0Kc2V0LnNlZWQoODE0KQphIDwtIGdyaWQ6OmFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGU9MjIuNSwgbGVuZ3RoID0gdW5pdCguMDc1LCAiaW5jaGVzIikpCncxdzIgPC0gc2hhayAlPiUKICBhc190aWJibGUoKSAlPiUKICBmaWx0ZXIoQWN0U2NlbmVMaW5lICE9ICIiKSAlPiUKICB1bm5lc3RfdG9rZW5zKGlucHV0ID0gUGxheWVyTGluZSwgb3V0cHV0ID0gdHJpZ3JhbSwgdG9rZW4gPSAibmdyYW1zIiwgbiA9IDMpICU+JQogIHNlcGFyYXRlKHRyaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiwgIndvcmQzIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgZmlsdGVyKCF3b3JkMyAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSB0aGlyZCBjb2x1bW4KICBjb3VudCh3b3JkMSwgd29yZDIsIHdvcmQzLCBzb3J0ID0gVFJVRSkgJT4lCiAgbXV0YXRlKHNldCA9IDEpICU+JQogIHRyYW5zbXV0ZSh3b3JkMT13b3JkMSx3b3JkMj13b3JkMixuPW4sc2V0PXNldCkKdzJ3MyA8LSBzaGFrICU+JQogIGFzX3RpYmJsZSgpICU+JQogIGZpbHRlcihBY3RTY2VuZUxpbmUgIT0gIiIpICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSB0cmlncmFtLCB0b2tlbiA9ICJuZ3JhbXMiLCBuID0gMykgJT4lCiAgc2VwYXJhdGUodHJpZ3JhbSwgYygid29yZDEiLCAid29yZDIiLCAid29yZDMiKSwgc2VwID0gIiAiKSAlPiUgIyBzZXBhcmF0ZXMgYmlncmFtIGludG8gdHdvIGNvbHVtbnMsIG9uZSBmb3IgZWFjaCB3b3JkCiAgZmlsdGVyKCF3b3JkMSAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBmaXJzdCBjb2x1bW4KICBmaWx0ZXIoIXdvcmQyICVpbiUgc2hha19zdG9wJHdvcmQpICU+JSAjIGZpbHRlcnMgc3RvcCB3b3JkcyBmcm9tIHNlY29uZCBjb2x1bW4KICBmaWx0ZXIoIXdvcmQzICVpbiUgc2hha19zdG9wJHdvcmQpICU+JSAjIGZpbHRlcnMgc3RvcCB3b3JkcyBmcm9tIHRoaXJkIGNvbHVtbgogIGNvdW50KHdvcmQxLCB3b3JkMiwgd29yZDMsIHNvcnQgPSBUUlVFKSAlPiUKICBtdXRhdGUoc2V0ID0gMikgJT4lCiAgdHJhbnNtdXRlKHdvcmQxPXdvcmQyLHdvcmQyPXdvcmQzLG49bixzZXQ9c2V0KQp3WHdZIDwtIGJpbmRfcm93cyh3MXcyLHcydzMpCgp3WHdZICU+JQogIGZpbHRlcihuPj0zKSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9ub2RlX3BvaW50KGNvbG9yID0gImxpZ2h0Ymx1ZSIsIHNpemUgPSA1KSArCiAgICBnZW9tX2VkZ2VfbGluayhhZXMoZWRnZV9hbHBoYSA9IG4pLCBlZGdlX2NvbG91cj0iZGFya2JsdWUiLCBzaG93LmxlZ2VuZCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgYXJyb3cgPSBhLCBlbmRfY2FwID0gY2lyY2xlKC4wNywgJ2luY2hlcycpKSArCiAgICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgYWxwaGE9Ljc1LCByZXBlbD1UUlVFKSArICMgLCB2anVzdCA9IDEsIGhqdXN0ID0gMSkgKwogICAgdGhlbWVfdm9pZCgpCmBgYAoKIyBIZWF0bWFwcwoKYGBge3J9CnNoYWsgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgI2ZpbHRlcihQbGF5ID09ICJIYW1sZXQiIHwgUGxheSA9PSAiTG92ZXMgTGFib3VycyBMb3N0IiB8IFBsYXkgPT0gIkEgV2ludGVycyBUYWxlIikgJT4lCiAgZmlsdGVyKEFjdFNjZW5lTGluZSAhPSAiIikgJT4lCiAgbXV0YXRlKEFjdFNjZW5lTGluZTIgPSBBY3RTY2VuZUxpbmUpICU+JQogIHNlcGFyYXRlKEFjdFNjZW5lTGluZTIsIGMoImFjdCIsICJzY2VuZSIsICJsaW5lIikpICU+JQogIGNvdW50KFBsYXksYWN0LHNjZW5lLCBzb3J0PVRSVUUpICU+JQogIHRyYW5zbXV0ZShwbGF5PVBsYXksIGFjdD1hcy5udW1lcmljKGFjdCksIHNjZW5lPWFzLm51bWVyaWMoc2NlbmUpLCBuPW4pCmBgYAoKCmBgYHtyfQpzaGFrICU+JQogIGFzX3RpYmJsZSgpICU+JQogIGZpbHRlcihQbGF5ID09ICJIYW1sZXQiIHwgUGxheSA9PSAiS2luZyBKb2huIiB8IFBsYXkgPT0gIlRoZSBUZW1wZXN0IiB8IAogICAgICAgICAgIFBsYXkgPT0gIkN5bWJlbGluZSIgfCBQbGF5ID09ICJNZWFzdXJlIGZvciBtZWFzdXJlIiB8IFBsYXkgPT0gIlRpbW9uIG9mIEF0aGVucyIgfCAKICAgICAgICAgICBQbGF5ID09ICJSaWNoYXJkIElJSSIgfCBQbGF5ID09ICJMb3ZlcyBMYWJvdXJzIExvc3QiIHwgUGxheSA9PSAiQSBXaW50ZXJzIFRhbGUiIHwgCiAgICAgICAgICAgUGxheSA9PSAiT3RoZWxsbyIgfCBQbGF5ID09ICJSb21lbyBhbmQgSnVsaWV0IiB8IFBsYXkgPT0gIkhlbnJ5IFYiKSAlPiUgCiAgZmlsdGVyKEFjdFNjZW5lTGluZSAhPSAiIikgJT4lCiAgbXV0YXRlKEFjdFNjZW5lTGluZTIgPSBBY3RTY2VuZUxpbmUpICU+JQogIHNlcGFyYXRlKEFjdFNjZW5lTGluZTIsIGMoImFjdCIsICJzY2VuZSIsICJsaW5lIikpICU+JQogIGNvdW50KFBsYXksYWN0LCBzb3J0PVRSVUUpICU+JQogIHRyYW5zbXV0ZShwbGF5PVBsYXksIGFjdD1hcy5pbnRlZ2VyKGFjdCksIG49bikgJT4lCiAgZ2dwbG90KGFlcyh4PWFjdCx5PXJlb3JkZXIocGxheSwgbikpKSArIAogICAgZ2VvbV90aWxlKGFlcyhmaWxsID0gbiksIGNvbG91ciA9ICJ3aGl0ZSIpICsgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAid2hpdGUiLCBoaWdoID0gInN0ZWVsYmx1ZSIpCmBgYAoKYGBge3J9CnNoYWsgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgZmlsdGVyKFBsYXkgPT0gIkhhbWxldCIgfCBQbGF5ID09ICJLaW5nIEpvaG4iIHwgUGxheSA9PSAiVGhlIFRlbXBlc3QiIHwgCiAgICAgICAgICAgUGxheSA9PSAiQ3ltYmVsaW5lIiB8IFBsYXkgPT0gIk1lYXN1cmUgZm9yIG1lYXN1cmUiIHwgUGxheSA9PSAiVGltb24gb2YgQXRoZW5zIiB8IAogICAgICAgICAgIFBsYXkgPT0gIlJpY2hhcmQgSUlJIiB8IFBsYXkgPT0gIkxvdmVzIExhYm91cnMgTG9zdCIgfCBQbGF5ID09ICJBIFdpbnRlcnMgVGFsZSIgfCAKICAgICAgICAgICBQbGF5ID09ICJPdGhlbGxvIiB8IFBsYXkgPT0gIlJvbWVvIGFuZCBKdWxpZXQiIHwgUGxheSA9PSAiSGVucnkgViIpICU+JSAKICBmaWx0ZXIoQWN0U2NlbmVMaW5lICE9ICIiKSAlPiUKICBtdXRhdGUoQWN0U2NlbmVMaW5lMiA9IEFjdFNjZW5lTGluZSkgJT4lCiAgc2VwYXJhdGUoQWN0U2NlbmVMaW5lMiwgYygiYWN0IiwgInNjZW5lIiwgImxpbmUiKSkgJT4lCiAgY291bnQoUGxheSxzY2VuZSwgc29ydD1UUlVFKSAlPiUKICB0cmFuc211dGUocGxheT1QbGF5LCBzY2VuZT1hcy5pbnRlZ2VyKHNjZW5lKSwgbj1uKSAlPiUKICBnZ3Bsb3QoYWVzKHg9c2NlbmUseT1yZW9yZGVyKHBsYXksIG4pKSkgKyAKICAgIGdlb21fdGlsZShhZXMoZmlsbCA9IG4pLCBjb2xvdXIgPSAid2hpdGUiKSArIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICJzdGVlbGJsdWUiKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMDo4KSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9NSwgZmlnLmFzcD0uMzV9CnNoYWsgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgZmlsdGVyKFBsYXkgPT0gIkhhbWxldCIgfCBQbGF5ID09ICJLaW5nIEpvaG4iIHwgUGxheSA9PSAiVGhlIFRlbXBlc3QiIHwgCiAgICAgICAgICAgUGxheSA9PSAiQ3ltYmVsaW5lIiB8IFBsYXkgPT0gIk1lYXN1cmUgZm9yIG1lYXN1cmUiIHwgUGxheSA9PSAiVGltb24gb2YgQXRoZW5zIiB8IAogICAgICAgICAgIFBsYXkgPT0gIlJpY2hhcmQgSUlJIiB8IFBsYXkgPT0gIkxvdmVzIExhYm91cnMgTG9zdCIgfCBQbGF5ID09ICJBIFdpbnRlcnMgVGFsZSIgfCAKICAgICAgICAgICBQbGF5ID09ICJPdGhlbGxvIiB8IFBsYXkgPT0gIlJvbWVvIGFuZCBKdWxpZXQiKSAlPiUgCiAgZmlsdGVyKEFjdFNjZW5lTGluZSAhPSAiIikgJT4lCiAgbXV0YXRlKEFjdFNjZW5lTGluZTIgPSBBY3RTY2VuZUxpbmUpICU+JQogIHNlcGFyYXRlKEFjdFNjZW5lTGluZTIsIGMoImFjdCIsICJzY2VuZSIsICJsaW5lIikpICU+JQogIGNvdW50KFBsYXksYWN0LHNjZW5lLCBzb3J0PVRSVUUpICU+JQogIHRyYW5zbXV0ZShwbGF5PVBsYXksIGFjdD1hcy5pbnRlZ2VyKGFjdCksIHNjZW5lPWFzLmludGVnZXIoc2NlbmUpLCBuPW4pICU+JQogIGdncGxvdChhZXMoeD1zY2VuZSx5PXBsYXkpKSArIAogICAgZ2VvbV90aWxlKGFlcyhmaWxsID0gbiksIGNvbG91ciA9ICJ3aGl0ZSIpICsgCiAgICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJ3aGl0ZSIsIGhpZ2ggPSAicmVkMiIpICsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygwOjgpKSArCiAgICB0aGVtZV9kYXJrKCkgKyAKICAgIGZhY2V0X3dyYXAofmFjdCwgbmNvbCA9IDUpCmBgYAoKCmBgYHtyIGZpZy53aWR0aD01LCBmaWcuYXNwPS41fQpzaGFrICU+JQogIGFzX3RpYmJsZSgpICU+JQogIGZpbHRlcihQbGF5ID09ICJIYW1sZXQiKSAlPiUgCiAgI2ZpbHRlcihQbGF5ZXIgIT0gIkhBTUxFVCIgJiBQbGF5ZXIgIT0gIkxPUkQgUE9MT05JVVMiICYgUGxheWVyICE9ICJLSU5HIENMQVVESVVTIikgJT4lIAogIGZpbHRlcihBY3RTY2VuZUxpbmUgIT0gIiIpICU+JQogIG11dGF0ZShBY3RTY2VuZUxpbmUyID0gQWN0U2NlbmVMaW5lKSAlPiUKICBzZXBhcmF0ZShBY3RTY2VuZUxpbmUyLCBjKCJhY3QiLCAic2NlbmUiLCAibGluZSIpKSAlPiUKICBjb3VudChQbGF5ZXIsYWN0LHNjZW5lLCBzb3J0PVRSVUUpICU+JQogIHRyYW5zbXV0ZShwbGF5ZXI9UGxheWVyLCBhY3Q9YXMuaW50ZWdlcihhY3QpLCBzY2VuZT1hcy5pbnRlZ2VyKHNjZW5lKSwgbj1uKSAlPiUKICBnZ3Bsb3QoYWVzKHg9c2NlbmUseT1yZW9yZGVyKHBsYXllcixuKSkpICsgCiAgICBnZW9tX3RpbGUoYWVzKGZpbGwgPSBuKSwgY29sb3VyID0gIndoaXRlIikgKyAKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICJyZWQyIikgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDA6OCkpICsKICAgIHRoZW1lX2RhcmsoKSArIAogICAgZmFjZXRfd3JhcCh+YWN0LCBuY29sID0gNSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9NSwgZmlnLmFzcD0uNX0Kc2hhayAlPiUKICBhc190aWJibGUoKSAlPiUKICBmaWx0ZXIoUGxheSA9PSAiVHdlbGZ0aCBOaWdodCIpICU+JSAKICAjZmlsdGVyKFBsYXllciAhPSAiSEFNTEVUIiAmIFBsYXllciAhPSAiTE9SRCBQT0xPTklVUyIgJiBQbGF5ZXIgIT0gIktJTkcgQ0xBVURJVVMiKSAlPiUgCiAgZmlsdGVyKEFjdFNjZW5lTGluZSAhPSAiIikgJT4lCiAgbXV0YXRlKEFjdFNjZW5lTGluZTIgPSBBY3RTY2VuZUxpbmUpICU+JQogIHNlcGFyYXRlKEFjdFNjZW5lTGluZTIsIGMoImFjdCIsICJzY2VuZSIsICJsaW5lIikpICU+JQogIGNvdW50KFBsYXllcixhY3Qsc2NlbmUsIHNvcnQ9VFJVRSkgJT4lCiAgdHJhbnNtdXRlKHBsYXllcj1QbGF5ZXIsIGFjdD1hcy5pbnRlZ2VyKGFjdCksIHNjZW5lPWFzLmludGVnZXIoc2NlbmUpLCBuPW4pICU+JQogIGdncGxvdChhZXMoeD1zY2VuZSx5PXBsYXllcikpICsgCiAgICBnZW9tX3RpbGUoYWVzKGZpbGwgPSBuKSwgY29sb3VyID0gIndoaXRlIikgKyAKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICJyZWQyIikgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDA6OCkpICsKICAgIHRoZW1lX2RhcmsoKSArIAogICAgZmFjZXRfd3JhcCh+YWN0LCBuY29sID0gNSkKYGBgCgojIyBXcmFwIHVwCgpXaGF0IHRoaXMgYWxsIHNlZW1zIHRvIHRlbGwgdXMgaXMgdGhhdCB3ZSBjYW4gdmlzdWFsaXNlIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIHBsYXksIHNlcGFyYXRlIGZyb20gdGhlaXIgY29udGVudC4gSXMgdGhpcyB1c2VmdWwgdG8geW91Pw==